package com.ruixin.base.util;

import com.ruixin.base.BaseTryCatch;
import com.ruixin.base.annotation.AnnotationHandler;
import com.ruixin.base.exception.BaseException;
import com.sun.istack.internal.NotNull;

import java.io.InputStream;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

/**
 * Created by Ruixin
 * Description:bean工具类
 */
public class BeanUtil {

    /**
     * 创建对象
     * @param clz
     * @param args
     * @param <T>
     * @return
     * @throws BaseException
     */
    public static <T> T newInstance(Class<T> clz,Object ... args) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<T>)()->{
            if(args.length==0) {
                return clz.newInstance();
            }
            Constructor<?> constructor = getConstructor(clz, args);
            return clz.cast(constructor.newInstance(args));
        });
    }

    /**
     * 获取构造器
     * @param clz
     * @param args
     * @return
     * @throws BaseException
     */
    public static Constructor<?> getConstructor(Class<?> clz,Object ... args) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<Constructor<?>>) ()->{
            if(args.length==0){
                return clz.getConstructor();
            }
            Constructor<?>[] constructors = clz.getDeclaredConstructors();
            for(Constructor constructor:constructors){
                int parameterCount = constructor.getParameterCount();
                if(parameterCount==args.length){
                    Class[] parameterTypes = constructor.getParameterTypes();
                    boolean found = true;
                    for(int i=0;i<parameterCount;i++){
                        Class<?> parameterType = parameterTypes[i];
                        Object arg = args[i];
                        if(parameterType!=arg.getClass()&&!parameterType.isAssignableFrom(arg.getClass())){
                            found = false;
                            break;
                        }
                    }
                    if(found){
                        constructor.setAccessible(true);
                        return constructor;
                    }
                }
            }
            return null;
        });
    }

    /**
     * 获取Class
     * @param className
     * @return
     * @throws BaseException
     */
    public static Class<?> newClass(String className) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<Class<?>>) ()->{
            return Class.forName(className);
        });
    }

    /**
     * 获取注解值
     * @param annotation
     * @return
     * @throws BaseException
     */
    public static Map<String,Object> getAnnotationValues(Annotation annotation) throws BaseException {
       return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<? extends Map<String, Object>>) ()->{
           InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
           Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
           memberValues.setAccessible(true);
           return (Map<String, Object>) memberValues.get(invocationHandler);
       });
    }

    /**
     * 获取注解
     * @param obj
     * @param clz
     * @param <T>
     * @return
     * @throws BaseException
     */
    public static <T extends Annotation> T getAnnotation(Object obj,Class<T> clz) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<T>)()->{
           T t = null;
           if(obj instanceof Class){
               t = ((Class<?>) obj).getAnnotation(clz);
           } else if(obj instanceof Field){
               t = ((Field) obj).getAnnotation(clz);
           }else if (obj instanceof Method){
               t = ((Method) obj).getAnnotation(clz);
           }else if(obj instanceof Parameter){
               t = ((Parameter) obj).getAnnotation(clz);
           }else {
               throw new BaseException("暂不支持该类型");
           }
           if(t==null){
                t = getSuperAnnotation(obj,clz);
           }
           return t;
        });
    }

    /**
     * 获取父类注解
     * @param obj
     * @param clz
     * @param <T>
     * @return
     * @throws BaseException
     */
    public static <T extends Annotation> T getSuperAnnotation(Object obj,Class<T> clz) throws BaseException {
        List<Annotation> annotations = getAnnotations(obj);
        for (Annotation annotation : annotations) {
            Class<? extends Annotation> aClass = annotation.annotationType();
            T superAnnotation = aClass.getAnnotation(clz);
            if(superAnnotation!=null){
                return AnnotationHandler.getSuperAnnotation(annotation,clz);
            }else{
                return getSuperAnnotation(aClass,clz);
            }
        }
        return null;
    }

    //忽略的注解
    public static List<Class<? extends Annotation>> ignoreAnnotations = Arrays.asList(Override.class,Target.class,
            Documented.class, Inherited.class, Retention.class, NotNull.class);

    /**
     * 获取注解
     * @param obj
     * @return
     * @throws BaseException
     */
    public static List<Annotation> getAnnotations(Object obj) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<? extends List<Annotation>>) ()->{
            Annotation[] annotations = null;
            if(obj instanceof Class){
                annotations = ((Class) obj).getAnnotations();
            }else if(obj instanceof Field){
                annotations = ((Field) obj).getAnnotations();
            }else if(obj instanceof Method){
                annotations = ((Method) obj).getAnnotations();
            }else if (obj instanceof Parameter){
                annotations = ((Parameter) obj).getAnnotations();
            }else {
                throw new BaseException("暂不支持该类型");
            }
            List<Annotation> annotationList = new ArrayList<>();
            for (Annotation annotation:annotations) {
                if(!ignoreAnnotations.contains(annotation.annotationType())){
                    annotationList.add(annotation);
                }
            }
            return annotationList;
        });
    }

    /**
     * 获取默认的名称
     * @param clz
     * @return
     */
    public static String getDefaultBeanName(Class<?> clz) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<String>) ()->{
            String simpleName = clz.getSimpleName();
            String preffix = simpleName.substring(0, 1);
            return preffix.toLowerCase()+simpleName.substring(1);
        });
    }

    /**
     * 设置Field的值
     * @param obj
     * @param field
     * @param value
     * @throws BaseException
     */
    public static void invokeField(Object obj,Field field,Object value) throws BaseException {
        BaseTryCatch.process(()->{
            field.setAccessible(true);
            field.set(obj,TypeConvertor.parseData(value,field.getType()));
        });
    }

    /**
     * 读取properties
     * @param filePath
     * @return
     * @throws BaseException
     */
    public static Properties getProperties(String filePath) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<Properties>) ()->{
            Properties properties = new Properties();
            InputStream inputStream = BeanUtil.class.getClassLoader().getResourceAsStream(filePath);
            if(inputStream!=null){
                properties.load(inputStream);
            }
            return properties;
        });
    }

    /**
     * 调用方法
     * @param obj
     * @param method
     * @param args
     * @return
     * @throws BaseException
     */
    public static Object invokeMethod(Object obj,Method method,Object ... args) throws BaseException {
        return BaseTryCatch.process((BaseTryCatch.CallBackWithResult<Object>) ()->{
            return method.invoke(obj, args);
        });
    }
}
